package com.ruoyi.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.constant.CacheConstants;
import com.ruoyi.common.core.constant.DeletedConstants;
import com.ruoyi.common.core.constant.OrderConstants;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.OrderNoUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.edu.api.domain.vo.EduCourseVO;
import com.ruoyi.edu.api.feign.IEduClient;
import com.ruoyi.order.api.domain.TOrder;
import com.ruoyi.order.api.domain.TPayLog;
import com.ruoyi.order.config.AliPayConfig;
import com.ruoyi.order.mapper.TOrderMapper;
import com.ruoyi.order.service.ITOrderService;
import com.ruoyi.order.service.ITPayLogService;
import com.ruoyi.user.api.domain.UcenterMember;
import com.ruoyi.user.api.feign.IUserClient;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;


/**
 * 订单Service业务层处理
 *
 * @author ruoyi
 * @date 2023-09-19
 */
@Service
public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> implements ITOrderService {
    @Resource
    private TOrderMapper tOrderMapper;
    @Resource
    private IUserClient iUserClient;
    @Resource
    private IEduClient iEduClient;
    @Resource
    private AliPayConfig aliPayConfig;
    @Resource
    private ITPayLogService itPayLogService;
    @Resource
    private RedisService redisService;

    /**
     * 查询订单
     *
     * @param id 订单主键
     * @return 订单
     */
    @Override
    public TOrder selectTOrderById(String id) {
        return tOrderMapper.selectTOrderById(id);
    }

    /**
     * 查询订单列表
     *
     * @param tOrder 订单
     * @return 订单
     */
    @Override
    public List<TOrder> selectTOrderList(TOrder tOrder) {
        return tOrderMapper.selectTOrderList(tOrder);
    }

    /**
     * 修改订单
     *
     * @param tOrder 订单
     * @return 结果
     */
    @Override
    public int updateTOrder(TOrder tOrder) {
        return tOrderMapper.updateById(tOrder);
    }

    /**
     * 批量删除订单
     *
     * @param ids 需要删除的订单主键
     * @return 结果
     */
    @Override
    public int deleteTOrderByIds(String[] ids) {
        return tOrderMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除订单信息
     *
     * @param id 订单主键
     * @return 结果
     */
    @Override
    public int deleteTOrderById(String id) {
        return tOrderMapper.deleteById(id);
    }

    @Override
    public boolean paidOrder(String orderNo, Integer payType) {
        // 更新订单状态为已支付
        LambdaQueryWrapper<TOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TOrder::getOrderNo, orderNo);
        TOrder one = getOne(wrapper);
        if (one == null) {
            return false;
        }
        one.setStatus(OrderConstants.PAID);
        updateById(one);
        // 创建支付日志
        TPayLog tPayLog = new TPayLog();
        tPayLog.setPayTime(new Date());
        tPayLog.setPayType(payType);
        tPayLog.setOrderNo(orderNo);
        tPayLog.setTradeState(OrderConstants.PAY_TYPE_SUCCESS);
        tPayLog.setIsDeleted(DeletedConstants.UN_DELETED);
        tPayLog.setTotalFee(one.getTotalFee());
        // 流水号随机生成
        tPayLog.setTransactionId(OrderNoUtils.getOrderNo());
        itPayLogService.save(tPayLog);
        // 异步记录此次购买
        recordBuy(one.getCourseId());
        return true;
    }

    /**
     * 每当会员购买课程时，给课程购买数加1
     * -> Redis记录，异步方法每5分钟执行一次，统计观看量并更新数据库
     *
     * @param courseId 被购买的课程id
     */
    @Async
    public void recordBuy(String courseId) {
        // 如果5分钟内已经有该课程的购买记录，则在原本基础上加一即可
        if (redisService.cacheMapExists(CacheConstants.VIDEO_BUYS, courseId)) {
            redisService.incrementCacheMapValue(CacheConstants.VIDEO_BUYS, courseId, 1);
        } else {
            // 否则添加对该视频观看次数的缓存
            redisService.setCacheMapValue(CacheConstants.VIDEO_BUYS, courseId, 1);
        }
    }

    @Override
    public String createOrders(String courseId, String memberId) {
        LambdaQueryWrapper<TOrder> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TOrder::getCourseId, courseId);
        queryWrapper.eq(TOrder::getMemberId, memberId);
        TOrder one = getOne(queryWrapper);
        if (null != one) {
            return "订单'" + one.getOrderNo() + "'已存在，正在为您跳转至支付页面";
        }
        TOrder tOrder = new TOrder();
        // 创建订单，需要远程获取用户昵称、手机号等信息
        AjaxResult memberInfo = iUserClient.getMemberInfo(memberId);
        if (!memberInfo.isSuccess()) {
            throw new ServiceException((String) memberInfo.get(AjaxResult.MSG_TAG));
        }
        UcenterMember member = JSON.parseObject(JSON.toJSONString(memberInfo.get(AjaxResult.DATA_TAG)), UcenterMember.class);
        tOrder.setMemberId(memberId);
        tOrder.setMobile(member.getMobile());
        tOrder.setNickname(member.getNickname());
        // 再远程获取课程信息
        AjaxResult courseInfo = iEduClient.getCourseInfo(courseId);
        if (!courseInfo.isSuccess()) {
            throw new ServiceException((String) courseInfo.get(AjaxResult.MSG_TAG));
        }
        EduCourseVO courseVO = JSON.parseObject(JSON.toJSONString(courseInfo.get(AjaxResult.DATA_TAG)), EduCourseVO.class);
        tOrder.setCourseId(courseId);
        tOrder.setCourseCover(courseVO.getCover());
        tOrder.setCourseTitle(courseVO.getTitle());
        tOrder.setTeacherName(courseVO.getTeacherName());
        tOrder.setTotalFee(courseVO.getPrice());
        // 初始化订单状态
        tOrder.setIsDeleted(DeletedConstants.UN_DELETED);
        tOrder.setStatus(OrderConstants.UN_PAY);
        tOrder.setOrderNo(OrderNoUtils.getOrderNo());
        tOrder.setPayType(OrderConstants.PAID_TYPE_WX);
        // 成功创建订单则返回订单号，否则返回null
        return save(tOrder) ? "生成订单成功，您的订单号为:'" + tOrder.getOrderNo() + "',正在为您跳转至支付页面" : null;
    }

    @Override
    public void aliPay(String orderNo, HttpServletResponse httpResponse) throws IOException {
        // 0. 查询订单详情
        LambdaQueryWrapper<TOrder> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TOrder::getOrderNo, orderNo);
        TOrder one = getOne(queryWrapper);
        if (null == one) {
            throw new ServiceException("获取订单信息失败，请重新生成订单");
        }
        // 1. 创建Client，通用SDK提供的Client，负责调用支付宝的API
        AlipayClient alipayClient = new DefaultAlipayClient(aliPayConfig.getGatewayUrl(), aliPayConfig.getAppId(),
                aliPayConfig.getAppPrivateKey(), "json", aliPayConfig.getCharset(), aliPayConfig.getAlipayPublicKey(), aliPayConfig.getSignType());
        // 2. 创建 Request并设置Request参数
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setNotifyUrl(aliPayConfig.getNotifyUrl());
        // 我们自己生成的订单信息
        request.setBizContent("{\"out_trade_no\":\"" + orderNo + "\","
                + "\"total_amount\":\"" + one.getTotalFee() + "\","
                + "\"subject\":\"" + one.getCourseTitle() + "\","
                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
        // 订单支付方式更改
        one.setPayType(OrderConstants.PAID_TYPE_ZFB);
        updateById(one);
        // 执行请求，拿到响应的结果，返回给浏览器
        String form = "";
        try {
            // 调用SDK生成表单
            form = alipayClient.pageExecute(request).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        httpResponse.setContentType("text/html;charset=utf-8");
        // 直接将完整的表单html输出到页面
        httpResponse.getWriter().write(form);
        httpResponse.getWriter().flush();
        httpResponse.getWriter().close();
    }

    @Override
    public String payNotify(HttpServletRequest request) throws AlipayApiException {
        if (OrderConstants.ALI_STATUS_SUCCESS.equals(request.getParameter(OrderConstants.ALI_STATUS))) {
            Map<String, String[]> requestParams = request.getParameterMap();
            Set<String> strings = requestParams.keySet();
            Map<String, String> params = new HashMap<>(strings.size());
            for (String name : strings) {
                params.put(name, request.getParameter(name));
            }
            String outTradeNo = params.get("out_trade_no");
            String sign = params.get("sign");
            String content = AlipaySignature.getSignCheckContentV1(params);
            // 验证签名，通过即可
            if (AlipaySignature.rsa256CheckContent(content, sign, aliPayConfig.getAlipayPublicKey(), aliPayConfig.getCharset())) {
                return outTradeNo;
            }
        }
        return null;
    }
}
